use std::sync::{
    mpsc::{channel, Receiver, Sender},
    Arc,
};

use egui::{
    include_image, Align, Align2, Color32, Id, Image, Key, LayerId, Layout, Margin, Modifiers,
    Pos2, Rect, Rounding, Sense, Stroke, Vec2,
};
use QcUI::{
    component::{Canvas, Label, UiNode, UiNodeTrait, Widget},
    core::{context::UiContext, layer::Layer},
};

use crate::{
    components::dock::DockView,
    core::{
        context::Context,
        editor_actions,
        message::{EditorMessage, ObjectType},
    },
    panel::UiNodeExt,
};

use super::UiPanelState;

pub enum UiPanelMessage {
    IsCapture(bool),
}

#[derive(Debug)]
pub struct UiPanel {
    context: Arc<Context>,
    editor_sender: Sender<EditorMessage>,
    state: UiPanelState,
    pub sender: Sender<UiPanelMessage>,
    receiver: Receiver<UiPanelMessage>,
}

impl DockView for UiPanel {
    fn update(&mut self, ctx: &mut UiContext, show_tab: bool) {
        while let Ok(msg) = self.receiver.try_recv() {
            match msg {
                UiPanelMessage::IsCapture(is_capture) => {
                    println!("{:?}", is_capture);
                    self.state.is_capture = is_capture;
                }
            }
        }
    }

    fn render(&mut self, ctx: &mut UiContext, show_tab: bool) {
        let mut scene_manager = self.context.scene_manager.try_write().unwrap();

        let scene = scene_manager.get_current_scene_mut().unwrap();

        let editor_actions = self.context.editor_actions.clone();
        if let Some(index) = scene.get_main_canvas() {
            let obj = &mut scene[index];
            if let Some(canvas) = obj.getComponentMut::<Canvas>() {
                canvas.update();

                let children = canvas.children.clone();

                let clip_rect = ctx.ui.clip_rect();

                let mut child = ctx
                    .ui
                    .child_ui(clip_rect, egui::Layout::top_down(egui::Align::Min));

                child.set_clip_rect(clip_rect);

                // 设置画布尺寸
                let width = clip_rect.width();

                let height = clip_rect.height();

                // 游戏界面距离左上角的偏移
                let offset = self.state.get_offset();

                egui::Frame::none()
                    .fill(Color32::GRAY)
                    .outer_margin(Margin {
                        left: self.state.offset.x,
                        right: 0.,
                        top: self.state.offset.y,
                        bottom: 0.,
                    })
                    .stroke(Stroke::new(1., Color32::BLACK))
                    .show(&mut child, |ui| {
                        ui.set_width(width);
                        ui.set_height(height);
                        ui.set_clip_rect(clip_rect);
                        let offset = ui.clip_rect().min;
                        let canvas_ptr = canvas as *mut Canvas;
                        for node in canvas.iter_mut() {
                            Self::draw_ui_node(
                                node.1,
                                &mut UiContext::new(ui, &ctx.sender.clone())
                                    .with_canvas_ptr(canvas_ptr),
                                offset,
                                self.state.get_offset(),
                            );
                        }
                    });

                self.draw_gizmo(canvas, ctx, clip_rect.min);

                if !self.state.is_capture {
                    return;
                }

                ctx.ui.input(|input| {
                    let delta = input.pointer.delta();

                    if let Some(pos) = input.pointer.interact_pos() {
                        // 转换坐标系
                        let pos = pos - ctx.ui.clip_rect().min - self.state.get_offset();

                        if input.pointer.primary_clicked() {
                            for (index, node) in canvas.iter() {
                                let widget = node.get_widget();

                                if widget.hit_test(pos.to_pos2()) {
                                    editor_actions
                                        .select_with_type(ObjectType::UiObject, Some(index));
                                    println!("点中了{:?}", editor_actions.get_type());
                                }
                            }
                        }

                        if input.pointer.primary_down() {
                            if let Some(index) = editor_actions.get_current_ui_node() {
                                let widget = canvas[index].get_widget();

                                if self.state.move_gizmo.is_some() {
                                } else if self.state.move_item.is_some() {
                                } else if let Some(align) =
                                    Self::hit_test_with_gizmo(widget, pos.to_pos2())
                                {
                                    self.state.move_item = Some(index);
                                    self.state.move_gizmo = Some(align);
                                } else if widget.hit_test(pos.to_pos2()) {
                                    self.state.move_item = Some(index);
                                }
                            }

                            if let Some(mode_item) = self.state.move_item {
                                let widget = canvas[mode_item].get_widget_mut();
                                if let Some(align) = self.state.move_gizmo {
                                    Self::move_gizmo(widget, align, delta);
                                } else {
                                    widget.position += delta;
                                }
                            }
                        }

                        if input.pointer.primary_released() {
                            self.state.move_item = None;
                            self.state.move_gizmo = None;
                        }
                    }

                    if input.pointer.secondary_down() {
                        self.state.translate(delta);
                    }

                    // 删除当前选中的对象
                    if input.key_released(Key::Delete) {
                        if let Some(target) = self.context.editor_actions.get_current_ui_node() {
                            self.editor_sender
                                .send(EditorMessage::RemoveUiNode(target))
                                .unwrap();
                        }
                    }
                });

                ctx.ui.input_mut(|input| {
                    // 保存场景
                    if input.consume_key(Modifiers::CTRL, Key::S) {
                        self.editor_sender.send(EditorMessage::SaveScene).unwrap();
                    }
                });
            }
        }
    }

    fn on_active(&self) {
        let edtion_actions = self.context.editor_actions.clone();
        edtion_actions.set_type(ObjectType::UiObject);
        println!("进入界面编辑器")
    }
}

impl UiPanel {
    pub fn new(context: Arc<Context>, editor_sender: Sender<EditorMessage>) -> Self {
        let (sender, receiver) = channel();
        Self {
            context,
            editor_sender,
            state: Default::default(),
            sender,
            receiver,
        }
    }

    pub fn draw_ui_node(node: &mut UiNode, ctx: &mut UiContext, fixed: Pos2, offset: Vec2) {
        let frame = node.renderFrame(ctx);
        let UiContext {
            ui,
            sender,
            canvas_ptr,
        } = ctx;

        let widget = node.get_widget();

        // 只渲染默认层级的组件
        if widget.layer != Layer::Default {
            return;
        }

        let pos = widget.world_position.to_vec2() + fixed.to_vec2() + offset;

        let rect = Rect::from_min_size(pos.to_pos2(), Vec2::new(widget.width, widget.height));

        let mut child = ctx
            .ui
            .child_ui(rect, egui::Layout::top_down(egui::Align::Min));

        frame.show(&mut child, |ui| {
            node.renderInner(&mut UiContext::new(ui, sender).with_canvas_ptr(*canvas_ptr))
        });
    }

    pub fn draw_gizmo(&self, canvas: &Canvas, ctx: &mut UiContext, fixed: Pos2) {
        let editor_actions = self.context.editor_actions.clone();

        if let Some(index) = editor_actions.get_current_ui_node() {
            let widget = canvas[index].get_widget();

            if widget.layer != Layer::Default {
                return;
            }
            
            let pos = widget.position + fixed.to_vec2() + self.state.get_offset();
            let rect = Rect::from_min_size(pos, widget.get_size());
            let painter = ctx.ui.painter();

            painter.rect_stroke(
                rect,
                Rounding::ZERO,
                Stroke::new(1.5, Color32::from_rgb(77, 196, 255)),
            );

            let step_x = rect.width() / 2.;
            let step_y = rect.height() / 2.;

            let point = rect.min;

            for x in 0..=2 {
                for y in 0..=2 {
                    if x == 1 && y == 1 {
                        continue;
                    }

                    let point =
                        Pos2::new(point.x + (x as f32) * step_x, point.y + (y as f32) * step_y);
                    let rect = Rect::from_center_size(point, Vec2::new(10., 10.));

                    painter.rect_filled(rect, Rounding::ZERO, Color32::WHITE);
                    painter.rect_stroke(
                        rect,
                        Rounding::ZERO,
                        Stroke::new(1.5, Color32::from_rgb(77, 196, 255)),
                    );
                }
            }
        }
    }

    pub fn hit_test_with_gizmo(widget: &Widget, position: Pos2) -> Option<Align2> {
        let pos = widget.position;
        let rect = Rect::from_min_size(pos, widget.get_size());
        let step_x = rect.width() / 2.;
        let step_y = rect.height() / 2.;

        let point = rect.min;

        let mut align = (-1, -1);
        for x in 0..=2 {
            for y in 0..=2 {
                if x == 1 && y == 1 {
                    continue;
                }

                let point = Pos2::new(point.x + (x as f32) * step_x, point.y + (y as f32) * step_y);
                let rect = Rect::from_center_size(point, Vec2::new(10., 10.));

                if rect.contains(position) {
                    align = (x, y);
                }
            }
        }

        match align {
            (0, 0) => Some(Align2::LEFT_TOP),
            (1, 0) => Some(Align2::CENTER_TOP),
            (2, 0) => Some(Align2::RIGHT_TOP),
            (0, 1) => Some(Align2::LEFT_CENTER),
            (2, 1) => Some(Align2::RIGHT_CENTER),
            (0, 2) => Some(Align2::LEFT_BOTTOM),
            (1, 2) => Some(Align2::CENTER_BOTTOM),
            (2, 2) => Some(Align2::RIGHT_BOTTOM),
            _ => None,
        }
    }

    fn move_gizmo(widget: &mut Widget, align: Align2, delta: Vec2) {
        // 坐标轴原点在左上角 x轴向右 y轴向下
        match align {
            Align2::LEFT_TOP => {
                widget.position += delta;
                widget.width -= delta.x;
                widget.height -= delta.y;
            }
            Align2::CENTER_TOP => {
                widget.position.y += delta.y;
                widget.height -= delta.y;
            }
            Align2::RIGHT_TOP => {
                widget.position.y += delta.y;
                widget.width += delta.x;
                widget.height -= delta.y;
            }
            Align2::LEFT_CENTER => {
                widget.position.x += delta.x;
                widget.width -= delta.x;
            }
            Align2::RIGHT_CENTER => {
                widget.width += delta.x;
            }
            Align2::LEFT_BOTTOM => {
                widget.height += delta.y;
                widget.width -= delta.x;
                widget.position.x += delta.x;
            }
            Align2::CENTER_BOTTOM => {
                widget.height += delta.y;
            }
            Align2::RIGHT_BOTTOM => {
                widget.width += delta.x;
                widget.height += delta.y;
            }
            _ => {}
        };
    }
}
